package com.jzo2o.health.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.trade.NativePayApi;
import com.jzo2o.api.trade.RefundRecordApi;
import com.jzo2o.api.trade.TradingApi;
import com.jzo2o.api.trade.dto.request.NativePayReqDTO;
import com.jzo2o.api.trade.dto.response.ExecutionResultResDTO;
import com.jzo2o.api.trade.dto.response.NativePayResDTO;
import com.jzo2o.api.trade.dto.response.TradingResDTO;
import com.jzo2o.api.trade.enums.PayChannelEnum;
import com.jzo2o.api.trade.enums.TradingStateEnum;
import com.jzo2o.common.expcetions.BadRequestException;

import com.jzo2o.common.expcetions.DBException;
import com.jzo2o.common.model.CurrentUserInfo;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.health.enums.OrderPayStatusEnum;
import com.jzo2o.health.enums.OrderStatusEnum;
import com.jzo2o.health.mapper.MemberMapper;
import com.jzo2o.health.mapper.OrdersCancelledMapper;
import com.jzo2o.health.mapper.OrdersMapper;
import com.jzo2o.health.mapper.SetmealMapper;

import com.jzo2o.health.model.UserThreadLocal;
import com.jzo2o.health.model.domain.*;

import com.jzo2o.health.model.dto.request.OrdersCancelReqDTO;
import com.jzo2o.health.model.dto.request.OrdersPageQueryReqDTO;
import com.jzo2o.health.model.dto.request.PlaceOrderReqDTO;
import com.jzo2o.health.model.dto.response.*;
import com.jzo2o.health.properties.TradeProperties;
import com.jzo2o.health.service.IOrdersService;

import com.jzo2o.mvc.utils.UserContext;
import com.jzo2o.mysql.utils.PageUtils;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;


/**
 * @Description IOrdersServiceImpl
 * @Author liujiangyuan
 * @Date 2024-12-14-15:07
 */

@Service
public class IOrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersService {
    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private SetmealMapper setmealMapper;
    @Autowired
    private MemberMapper memberMapper;
    @Override
    public PlaceOrderResDTO placeOrder(PlaceOrderReqDTO placeOrderReqDTO) {
        if (ObjectUtils.isEmpty(placeOrderReqDTO)){
            throw new BadRequestException("请求信息错误");
        }
        Orders ordersuser = BeanUtil.toBean(placeOrderReqDTO, Orders.class);
        Long order = this.getOrder(placeOrderReqDTO.getReservationDate());
        ordersuser.setId(order);
        PlaceOrderResDTO placeOrderResDTO = new PlaceOrderResDTO();
        placeOrderResDTO.setId(order);
        ordersuser.setOrderStatus(0);
        ordersuser.setPayStatus(0);
        Setmeal setmeal = setmealMapper.selectById(placeOrderReqDTO.getSetmealId());
        ordersuser.setSetmealPrice(BigDecimal.valueOf(setmeal.getPrice()));
        ordersuser.setSetmealName(setmeal.getName());
        ordersuser.setSetmealId(setmeal.getId());
        ordersuser.setSetmealImg(setmeal.getImg());
        ordersuser.setSetmealAge(setmeal.getAge());
        ordersuser.setSetmealRemark(setmeal.getRemark());
        ordersuser.setSetmealSex(setmeal.getSex());
        CurrentUserInfo currentUserInfo = UserThreadLocal.currentUser();
        ordersuser.setMemberId(currentUserInfo.getId());
        Member member = memberMapper.selectById(currentUserInfo.getId());
        ordersuser.setMemberPhone(member.getPhone());
        iOrdersService.add(ordersuser);
        return placeOrderResDTO;
    }
    @Autowired
    private TradeProperties tradeProperties;
    @Autowired
    private NativePayApi nativePayApi;
    @Autowired
    private IOrdersService iOrdersService;

    @Override
    public OrdersPayResDTO pay(Long id, PayChannelEnum tradingChannel) {
        Orders orders = this.getById(id);
        if (orders == null) {
            throw new BadRequestException("订单不存在");
        }
        //2. 判断订单是否已支付成功（支付状态和交易单号）
        if (ObjectUtils.equals(orders.getPayStatus(), OrderPayStatusEnum.PAY_SUCCESS.getStatus())
                && ObjectUtils.isNotNull(orders.getTradingOrderNo())) {
            OrdersPayResDTO ordersPayResDTO = BeanUtils.copyBean(orders, OrdersPayResDTO.class);
            ordersPayResDTO.setProductOrderNo(id);
            return ordersPayResDTO;
        }
        //3. 调用支付服务的Feign接口，获取响应数据

        //3.1 根据支付渠道获取商户号
        Long enterpriseId = ObjectUtils.equals(tradingChannel, PayChannelEnum.WECHAT_PAY) ? tradeProperties.getWechatEnterpriseId()
                : tradeProperties.getAliEnterpriseId();
        //3.2 判断是否更换过支付渠道 （订单已有支付渠道，且与本次请求参数的支付渠道不一样，就算更换过）
        boolean changeChannel = false; //默认值：未更换
        if (ObjectUtils.isNotNull(orders.getTradingChannel()) && ObjectUtils.notEqual(orders.getTradingChannel(), tradingChannel)) {
            changeChannel = true;
        }
        //业务系统唯一标识
        String productAppId = tradeProperties.getProductAppId();
        //3.3 发起feign接口请求调用支付服务，获取响应数据
        NativePayReqDTO nativePayReqDTO = new NativePayReqDTO();
        nativePayReqDTO.setProductOrderNo(id); //业务系统订单号（订单表的订单ID值）
        nativePayReqDTO.setEnterpriseId(enterpriseId);//商户号
        nativePayReqDTO.setProductAppId(productAppId);//业务系统唯一标识
        nativePayReqDTO.setChangeChannel(changeChannel);//是否更换过支付渠道
        nativePayReqDTO.setMemo(orders.getSetmealName());//商品描述
        //nativePayReqDTO.setTradingAmount(orders.getRealPayAmount());//订单金额：实际支付金额
        nativePayReqDTO.setTradingAmount(new BigDecimal(0.01));
        nativePayReqDTO.setTradingChannel(tradingChannel);//支付渠道

        NativePayResDTO nativePayResDTO = nativePayApi.createDownLineTrading(nativePayReqDTO);
        if (ObjectUtils.isNull(nativePayResDTO)) {
            throw new BadRequestException("调用支付服务的支付接口失败");
        }

        //4. 更新订单表数据（支付渠道和交易单号） update orders set trading_channel=?,trading_order_no=? where id=?
        iOrdersService.updateorder(id, nativePayResDTO);

        //5. 封装响应数据
        OrdersPayResDTO ordersPayResDTO = BeanUtils.copyBean(nativePayResDTO, OrdersPayResDTO.class);
        ordersPayResDTO.setPayStatus(orders.getPayStatus());
        return ordersPayResDTO;
    }

    @Autowired
    private RedisTemplate redisTemplate;
    private static final String ORDER_KEY = "ORDER_KEY";
    public Long getOrder(LocalDate date){
        String s = String.valueOf(date.getDayOfMonth());
        String s1 = String.valueOf(date.getMonthValue());
        String s2 = String.valueOf(date.getYear());
        String s3=s2+s1+s;
        Long l = Long.valueOf(s3);
        l=l*10000000L;
        Long increment = redisTemplate.opsForValue().increment(ORDER_KEY);
        return l+increment;

    }
    @Transactional(rollbackFor = Exception.class)
    public void add(Orders orders){

        boolean result = this.save(orders);
        if(!result) {
            throw new DBException("服务下单失败");
        }
    }
    @Transactional(rollbackFor = Exception.class)
    public void  updateorder(Long id,NativePayResDTO nativePayResDTO){
        boolean result = this.lambdaUpdate().eq(Orders::getId, id)
                .set(Orders::getTradingChannel, nativePayResDTO.getTradingChannel())
                .set(Orders::getTradingOrderNo, nativePayResDTO.getTradingOrderNo())
                .update();
        if(!result) {
            throw new DBException("支付失败");
        }
    }
    @Autowired
    private TradingApi tradingApi;

    @Override
    public OrdersPayResDTO payResult(Long id) {
        Orders orders = this.getById(id);
        if(orders==null) {
            throw new BadRequestException("订单不存在");
        }
        if(ObjectUtils.isNull(orders.getTradingOrderNo())) {
            throw new BadRequestException("非法订单");
        }
        OrdersPayResDTO ordersPayResDTO = BeanUtils.copyBean(orders, OrdersPayResDTO.class);
        ordersPayResDTO.setProductOrderNo(id);
        if(ObjectUtils.equals(orders.getPayStatus(),OrderPayStatusEnum.PAY_SUCCESS.getStatus())) {
            return ordersPayResDTO;
        }
        TradingResDTO tradingResDTO = tradingApi.findTradResultByTradingOrderNo(orders.getTradingOrderNo());
        if(ObjectUtils.isNotNull(tradingResDTO) && ObjectUtils.equals(tradingResDTO.getTradingState(), TradingStateEnum.YJS)) {
            iOrdersService.paySuccess(id,tradingResDTO.getTransactionId(),tradingResDTO.getPaySuccessTime());
            ordersPayResDTO.setQrCode(tradingResDTO.getQrCode());
            ordersPayResDTO.setPayStatus(OrderPayStatusEnum.PAY_SUCCESS.getStatus());
        }
        return ordersPayResDTO;

    }
    @Transactional(rollbackFor = Exception.class)
    public void paySuccess(Long orderId, String transactionId, LocalDateTime payTime) {
        boolean result = this.lambdaUpdate()
                .eq(Orders::getId, orderId)
                .set(Orders::getPayTime, payTime)
                .set(Orders::getTransactionId, transactionId)
                .set(Orders::getOrderStatus, OrderPayStatusEnum.PAY_SUCCESS.getStatus())
                .set(Orders::getPayStatus, OrderPayStatusEnum.PAY_SUCCESS.getStatus())
                .update();
        if(!result){
            throw new DBException("更新订单失败");
        }
    }
    @Autowired
    private OrdersCancelledMapper ordersCancelledMapper;
    @Autowired
    private RefundRecordApi refundRecordApi;
    @Override
    public void cancel(OrdersCancelReqDTO ordersCancelReqDTO) {
        Orders orders = this.getById(ordersCancelReqDTO.getId());
        OrdersCancelled ordersCanceled = new OrdersCancelled();
        ordersCanceled.setCancellerId(UserThreadLocal.currentUserId());
        ordersCanceled.setCancellerType(UserThreadLocal.currentUser().getUserType());
        ordersCanceled.setCancellerName(UserThreadLocal.currentUser().getName());
        ordersCanceled.setCancelReason(ordersCancelReqDTO.getCancelReason());
        ordersCanceled.setCancelTime(LocalDateTime.now());
        ordersCancelledMapper.insert(ordersCanceled);
        if (ObjectUtils.isEmpty(ordersCancelReqDTO)){
            throw new BadRequestException("请求信息错误");
        }
        boolean resultForOrders = this.lambdaUpdate()
                .eq(Orders::getId, ordersCancelReqDTO.getId())
                .set(Orders::getOrderStatus, OrderStatusEnum.CANCELLED.getStatus())
                .update();
        if(!resultForOrders) {
            throw new DBException("更新订单失败");
        }
    }
    @Override
    public void refund(OrdersCancelReqDTO ordersCancelReqDTO) {
        if (ObjectUtils.isEmpty(ordersCancelReqDTO)){
            throw new BadRequestException("请求信息错误");
        }
        Orders orders = this.getById(ordersCancelReqDTO.getId());
        if ((ObjectUtils.equals(orders.getOrderStatus(),OrderStatusEnum.WAITING_CHECKUP.getStatus())||
                (ObjectUtils.equals(orders.getOrderStatus(),OrderStatusEnum.COMPLETED_CHECKUP.getStatus())))){
            ExecutionResultResDTO executionResultResDTO = refundRecordApi.refundTrading(orders.getTradingOrderNo(),
                    orders.getSetmealPrice());
            if (executionResultResDTO.getRefundStatus()==2){
                this.lambdaUpdate().set(Orders::getOrderStatus,OrderStatusEnum.CANCELLED.getStatus())
                        .set(Orders::getPayStatus,OrderPayStatusEnum.REFUND_SUCCESS.getStatus())
                        .set(Orders::getRefundId,executionResultResDTO.getRefundId())
                        .set(Orders::getRefundNo,executionResultResDTO.getRefundNo())
                        .eq(Orders::getId,ordersCancelReqDTO.getId()).update();
            } else if (executionResultResDTO.getRefundStatus()==1) {
                this.lambdaUpdate().set(Orders::getOrderStatus,OrderStatusEnum.CANCELLED.getStatus())
                        .set(Orders::getPayStatus,OrderPayStatusEnum.REFUNDING.getStatus())
                        .set(Orders::getRefundId,executionResultResDTO.getRefundId())
                        .set(Orders::getRefundNo,executionResultResDTO.getRefundNo())
                        .eq(Orders::getId,ordersCancelReqDTO.getId()).update();
                OrdersCancelled ordersCanceled = new OrdersCancelled();
                ordersCanceled.setId(orders.getId());
                ordersCanceled.setCancellerId(UserThreadLocal.currentUserId());
                ordersCanceled.setCancellerType(UserThreadLocal.currentUser().getUserType());
                ordersCanceled.setCancellerName(UserThreadLocal.currentUser().getName());
                ordersCanceled.setCancelReason(ordersCancelReqDTO.getCancelReason());
                ordersCanceled.setCancelTime(LocalDateTime.now());
                ordersCancelledMapper.insert(ordersCanceled);
                OrdersRefund ordersRefund = new OrdersRefund ();
                ordersRefund.setId(ordersCancelReqDTO.getId());
                ordersRefund.setTradingOrderNo(orders.getTradingOrderNo());
                ordersRefund.setRealPayAmount(orders.getSetmealPrice());

            }else {
                throw new BadRequestException("退款失败");
            }

        }
    }

    @Override
    public List<OrdersResDTO> pageQuery(Integer ordersStatus, Long sortBy) {

        LambdaQueryWrapper<Orders> queryWrapper = Wrappers.<Orders>lambdaQuery()
                .eq(ObjectUtils.isNotNull(ordersStatus), Orders::getOrderStatus, ordersStatus)
                .lt(ObjectUtils.isNotNull(sortBy), Orders::getSortBy, sortBy);
        Page<Orders> page = new Page<>();
        page.addOrder(OrderItem.desc("sort_by"));
        page.setSearchCount(false);
        Page<Orders> ordersPage = baseMapper.selectPage(page, queryWrapper);
        List<Orders> records = ordersPage.getRecords();
        return BeanUtils.copyList(records, OrdersResDTO.class);
    }

    @Override
    public OrdersDetailResDTO detail(Long id) {
        Orders orders = this.getById(id);
        if (orders == null) {
            throw new BadRequestException("订单不存在");
        }
        OrdersDetailResDTO ordersDetailResDTO = BeanUtils.copyBean(orders, OrdersDetailResDTO.class);
        if (ordersDetailResDTO == null) {
            throw new BadRequestException("订单不存在");
        }
//        if (ordersDetailResDTO.getOrderStatus() == 400) {
//            OrdersCancelled ordersCancelled = ordersCancelledMapper.selectOne(Wrappers.<OrdersCancelled>lambdaQuery().eq(OrdersCancelled::getId,
//                    ordersDetailResDTO.getId()));
//            ordersDetailResDTO.setCancelReason(ordersCancelled.getCancelReason());
//        }
        return ordersDetailResDTO;
    }

    @Override
    public PageResult<OrdersResDTO> pageQueryadmin(OrdersPageQueryReqDTO ordersPageQueryReqDTO) {
        LambdaQueryWrapper<Orders> wrapper = Wrappers.<Orders>lambdaQuery()
                .eq(ObjectUtils.isNotEmpty(ordersPageQueryReqDTO.getOrderStatus()), Orders::getOrderStatus, ordersPageQueryReqDTO.getOrderStatus())
                .eq(ObjectUtils.isNotEmpty(ordersPageQueryReqDTO.getMemberPhone()), Orders::getMemberPhone, ordersPageQueryReqDTO.getMemberPhone());
        Page<Orders> page = PageUtils.parsePageQuery(ordersPageQueryReqDTO, Orders.class);
        Page<Orders> ordersList = baseMapper.selectPage(page, wrapper);
        return PageUtils.toPage(ordersList, OrdersResDTO.class);
    }

    @Override
    public AdminOrdersDetailResDTO aggregation(Long id) {
        Orders orders = getById(id);
        AdminOrdersDetailResDTO.OrderInfo orderInfo = new AdminOrdersDetailResDTO.OrderInfo();
        AdminOrdersDetailResDTO.PayInfo payInfo = new AdminOrdersDetailResDTO.PayInfo();
        AdminOrdersDetailResDTO.RefundInfo refundInfo = new AdminOrdersDetailResDTO.RefundInfo();
        AdminOrdersDetailResDTO.CancelInfo cancelInfo = new AdminOrdersDetailResDTO.CancelInfo();
        BeanUtils.copyProperties(orders, orderInfo);
        BeanUtils.copyProperties(orders, payInfo);
        BeanUtils.copyProperties(orders, refundInfo);
        BeanUtils.copyProperties(orders, cancelInfo);
        payInfo.setThirdOrderId(orders.getTransactionId());
        AdminOrdersDetailResDTO adminOrdersDetailResDTO = new AdminOrdersDetailResDTO();
        adminOrdersDetailResDTO.setCancelInfo(cancelInfo);
        adminOrdersDetailResDTO.setOrderInfo(orderInfo);
        adminOrdersDetailResDTO.setPayInfo(payInfo);
        adminOrdersDetailResDTO.setRefundInfo(refundInfo);
        return adminOrdersDetailResDTO;
    }

    @Override
    public OrdersCountResDTO countByStatus() {
        List<Orders> orders = ordersMapper.selectList(Wrappers.<Orders>lambdaQuery());
        OrdersCountResDTO ordersCountResDTO = new OrdersCountResDTO();
        ordersCountResDTO.setTotalCount(orders.size());
        Integer noPayCount = new Integer(0);
        Integer waitingCheckupCount = new Integer(0);
        Integer completedCheckupCount = new Integer(0);
        Integer closedCount = new Integer(0);
        Integer cancelledCount = new Integer(0);

        for (Orders order : orders) {
        if (order.getOrderStatus() == 0) {
            noPayCount++;
        } else if (order.getOrderStatus() == 100) {
            waitingCheckupCount++;
        }else if (order.getOrderStatus() == 200){
            completedCheckupCount++;
        } else if (order.getOrderStatus() == 300) {
            closedCount++;
        } else if (order.getOrderStatus() == 400) {
            cancelledCount++;
        }

        }
        ordersCountResDTO.setNoPayCount(noPayCount);
        ordersCountResDTO.setWaitingCheckupCount(waitingCheckupCount);
        ordersCountResDTO.setCompletedCheckupCount(completedCheckupCount);
        ordersCountResDTO.setClosedCount(closedCount);
        ordersCountResDTO.setCancelledCount(cancelledCount);

        return ordersCountResDTO;
    }


}
